<!DOCTYPE html>
<html  lang=zh>
  <head>
    <meta charset="utf-8">


    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    

    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="renderer" content="webkit">
    <meta http-equiv="Cache-Control" content="no-transform" />
    <meta http-equiv="Cache-Control" content="no-siteapp" />
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="format-detection" content="telephone=no,email=no,adress=no">
    <!-- Color theme for statusbar -->
    <meta name="theme-color" content="#000000" />
    <!-- 强制页面在当前窗口以独立页面显示,防止别人在框架里调用页面 -->
    <meta http-equiv="window-target" content="_top" />
  
    
    <title>vue响应式原理--Object.defineProperty &amp; proxy | Xowen Blog</title>
    <meta name="description" content="深入理解vue响应式原理学习vue有一段时间了，vue中核心思想就是数据响应式，实现了数据的双向绑定，减少了操作dom频次。 相信大家都有这个疑惑  Vue 内部是如何监听数据的改变？  vue2.x 采用Object.defineProperty -&gt; 监听对象属性的改变 vue3.x 采用proxy代理来实现  -&gt; 监听对象属性的改变   数据发生改变时，Vue是如何知道要通知哪">
<meta property="og:type" content="article">
<meta property="og:title" content="vue响应式原理--Object.defineProperty &amp; proxy">
<meta property="og:url" content="https://xowen.cn/2020/08/22/vue%E5%93%8D%E5%BA%94%E5%BC%8F%E5%8E%9F%E7%90%86-Object-defineProperty-proxy/index.html">
<meta property="og:site_name" content="xowen">
<meta property="og:description" content="深入理解vue响应式原理学习vue有一段时间了，vue中核心思想就是数据响应式，实现了数据的双向绑定，减少了操作dom频次。 相信大家都有这个疑惑  Vue 内部是如何监听数据的改变？  vue2.x 采用Object.defineProperty -&gt; 监听对象属性的改变 vue3.x 采用proxy代理来实现  -&gt; 监听对象属性的改变   数据发生改变时，Vue是如何知道要通知哪">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://s1.ax1x.com/2020/08/22/ddQyh6.jpg">
<meta property="article:published_time" content="2020-08-22T12:44:57.000Z">
<meta property="article:modified_time" content="2020-08-22T14:18:07.554Z">
<meta property="article:author" content="John Doe">
<meta property="article:tag" content="vue">
<meta property="article:tag" content="es6">
<meta property="article:tag" content="proxy">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://s1.ax1x.com/2020/08/22/ddQyh6.jpg">
    <!-- Canonical links -->
    <link rel="canonical" href="https://xowen.cn/2020/08/22/vue%E5%93%8D%E5%BA%94%E5%BC%8F%E5%8E%9F%E7%90%86-Object-defineProperty-proxy/index.html">
   
    
<link rel="stylesheet" href="/css/bootstrap.css">


    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.4.1/js/bootstrap.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.0/js/bootstrap.bundle.min.js"></script>
    
<link rel="stylesheet" href="/css/mainstyle.css">

    <link href="https://cdn.bootcdn.net/ajax/libs/highlight.js/10.0.1/styles/atom-one-dark-reasonable.min.css" rel="stylesheet">
    <link rel="shortcut icon" href="/images/bitbug_favicon.ico" type="image/x-icon">
    <link rel="stylesheet" href="//at.alicdn.com/t/font_1798605_rglfsa36dt.css">
    <script type="module" src="https://cdn.bootcdn.net/ajax/libs/instant.page/3.0.0/instantpage.min.js"></script>
    
    <script>
      (function(){
          var bp = document.createElement('script');
          var curProtocol = window.location.protocol.split(':')[0];
          if (curProtocol === 'https') {
              bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
          }
          else {
              bp.src = 'http://push.zhanzhang.baidu.com/push.js';
          }
          var s = document.getElementsByTagName("script")[0];
          s.parentNode.insertBefore(bp, s);
      })();
      </script>
      
  <meta name="generator" content="Hexo 4.2.0"></head>
<body class="myBody">
      <!-- header -->
  <div class="container-fluid ani-box x-nav" style=" box-shadow: 0 5px 15px 0 rgb(0 0 0 / 15%);">
    <div class="container">
      <nav class="navbar navbar-expand-lg navbar-light">
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
          aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
        <a class="navbar-brand" href="/">Xowen</a>


        <div class="collapse navbar-collapse" id="navbarSupportedContent">
          <ul class="navbar-nav mr-auto">
            <li class="nav-item active">
              <a class="nav-link" href="/">首页<span class="sr-only">(current)</span></a>
            </li>
            <li class="nav-item dropdown">
              <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown"
                aria-haspopup="true" aria-expanded="false">
                分类
              </a>
              <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/nexo%E5%BC%80%E5%8F%91/">nexo开发</a><span class="category-list-count">11</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/">博客搭建</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%AD%A6%E4%B9%A0%E6%97%A5%E8%AE%B0/">学习日记</a><span class="category-list-count">7</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</a><span class="category-list-count">7</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E7%94%9F%E6%B4%BB%E6%97%A5%E5%BF%97/">生活日志</a><span class="category-list-count">3</span></li></ul>
                <!-- <div class="dropdown-divider"></div> -->
                <!-- <a class="dropdown-item" href="#">Something else here</a> -->
              </div>
            </li>
            
              <li class="nav-item">
                <a class="nav-link" href="/archives">Xowen's 归档</a>
              </li>
            
              <li class="nav-item">
                <a class="nav-link" href="/message">留言板</a>
              </li>
            
              <li class="nav-item">
                <a class="nav-link" href="/about">关于Xowen</a>
              </li>
            
          
          </ul>
          <ul class="nav justify-content-end right-links">
            
              <li class="nav-item">
                <i class="iconfont icon-QQ"></i>
                <a class="nav-user" href="tencent://QQInterLive/?Cmd=2&Uin=1941352853" target="_blank">QQ</a>
              </li>
            
              <li class="nav-item">
                <i class="iconfont icon-git"></i>
                <a class="nav-user" href="https://github.com/DriverOwen/DriverOwen.github.io" target="_blank">GitHub</a>
              </li>
            
            <li class="nav-item" >
              <div class="checkbox">
                <input type="checkbox" data-toggle="tooltip" data-placement="right" title="打开看板娘!"  id="live2dButton">
                <label></label>
              </div>
            </li>
            
          </ul>
        </div>
        <a class="navbar-brand" href="#"></a>
      </nav>
    </div>
  </div>
  <div class="container x-padding ani-box cover-container">
    <div class="xowen-cover-wrapper">
      <div class="xowen-cover" >

      </div>
    </div>
    <div class="row x-top-info">
      <div class="col-md-7">
        <div class="xowen-info">
          <div class="xowen-user">
            <a class="top-avatar" href="javascript:;"><img src="https://s1.ax1x.com/2020/05/09/YlOkAf.jpg" alt="Xowen"></a>
            <div class="xowen-texts">
              <p class="top-title x-no"><a href="javascript:;">Good good study, and day day up.</a></p>
              <p class="top-text x-no"><a target="_blank" href="https://xowen.cn">睡觉是最大的爱好</a></p>
            </div>
          </div>

        </div>
      </div>
      <div class="col-md-5">
        <div class="x-num-info">
          <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
          <div class="x-stats" id="busuanzi_container_site_pv">
            <p class="x-stats-title x-no" id="busuanzi_value_site_pv">loading...</p>
            <p class="x-stats-text x-no " id="">VISITS</p>
          </div>
          <div class="x-stats">
            <p class="x-stats-title x-no" id="SURVIVA">loadings...</p>
            <p class="x-stats-text x-no">SURVIVA</p>
            <script>
              var now = new Date();
              (function createtime() {
                  var grt= new Date("5/10/2020 13:14:21");
                  now.setTime(now.getTime()+250);
                  days = (now - grt ) / 1000 / 60 / 60 / 24; dnum = Math.floor(days);
                 
                  document.getElementById("SURVIVA").innerHTML = dnum+" Days";
              })()
        
          </script>
          </div>
          <div class="x-stats">
            
            <p class="x-stats-title x-no">30</p>
            <p class="x-stats-text x-no">POSTS</p>
          </div>
          <div class="x-stats">
            <p class="x-stats-title x-no">24.1k</p>
            <p class="x-stats-text x-no">WORDS</p>
          </div>
        </div>
      </div>
    </div>
    <nav aria-label="breadcrumb">
      <ol class="breadcrumb">
     
       首页 / 2020 / 08 / 22 / vue响应式原理-Object-defineProperty-proxy / 
     
      </ol>
    </nav>
  </div>
 
    <div class="container x-main-content ani-box">
      <div class="row">
    <div class="col-md-3 x-side-box">
    <div class="card" style="width: auto;">
      <img class="card-img-top" src="https://s1.ax1x.com/2020/05/10/Y1WAjU.jpg" alt="Card image cap">
      <div class="card-body">
        <h5 class="card-title">公告</h5>
        <p class="card-text" style="text-align: justify;">大家好，我是xowen，欢迎访问我的博客！ </p>
      </div>
    </div>

   
    
      <div class="card" style="width: auto;">
  <div class="card-body">
    <h5 class="card-title">分类</h5>
    <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/nexo%E5%BC%80%E5%8F%91/">nexo开发</a><span class="category-list-count">11</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/">博客搭建</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%AD%A6%E4%B9%A0%E6%97%A5%E8%AE%B0/">学习日记</a><span class="category-list-count">7</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</a><span class="category-list-count">7</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E7%94%9F%E6%B4%BB%E6%97%A5%E5%BF%97/">生活日志</a><span class="category-list-count">3</span></li></ul>
  </div>
</div>
    
      <div class="card" style="width: auto;">
  <div class="card-body">
    <h5 class="card-title">最新文章</h5>
    <ul class="list-group list-group-flush">
      
    
      <li class="list-group-item">
        <img src="https://s1.ax1x.com/2020/05/09/YlOkAf.jpg" alt="" class="x-article-cover-img">
          <div class="hot-article">
            <a href="/2021/03/21/2021-3-20-python%E6%B8%A9%E4%B9%A0%E5%92%8C%E6%B3%A8%E6%84%8F%E7%82%B9/">2021-3-20-python温习和注意点...</a>
            <p class="hot-article-stats x-no">共 860 字</p>
          </div>
      </li>
      
    
      <li class="list-group-item">
        <img src="https://s1.ax1x.com/2020/05/09/YlOkAf.jpg" alt="" class="x-article-cover-img">
          <div class="hot-article">
            <a href="/2021/03/21/2021-3-20-blog%E6%9B%B4%E6%96%B0-%E9%B8%BD%E4%BA%86%E5%B0%86%E8%BF%91%E5%8D%8A%E5%B9%B4%E4%BA%86/">2021.3.20 blog更新 鸽了将近半年了...</a>
            <p class="hot-article-stats x-no">共 91 字</p>
          </div>
      </li>
      
    
      <li class="list-group-item">
        <img src="https://s1.ax1x.com/2020/05/09/YlOkAf.jpg" alt="" class="x-article-cover-img">
          <div class="hot-article">
            <a href="/2020/09/05/Chrome%E6%B5%8F%E8%A7%88%E5%99%A8%E8%B7%A8%E5%9F%9Fcookie%E6%97%A0%E6%B3%95%E6%90%BA%E5%B8%A6/">Chrome浏览器跨域cookie无法携带...</a>
            <p class="hot-article-stats x-no">共 759 字</p>
          </div>
      </li>
      
    
      <li class="list-group-item">
        <img src="https://s1.ax1x.com/2020/05/09/YlOkAf.jpg" alt="" class="x-article-cover-img">
          <div class="hot-article">
            <a href="/2020/08/27/%E6%B7%B1%E5%85%A5%E5%AD%A6%E4%B9%A0js-generator%E5%87%BD%E6%95%B0/">深入学习js-generator函数...</a>
            <p class="hot-article-stats x-no">共 1.2k 字</p>
          </div>
      </li>
      
    
      <li class="list-group-item">
        <img src="https://s1.ax1x.com/2020/05/09/YlOkAf.jpg" alt="" class="x-article-cover-img">
          <div class="hot-article">
            <a href="/2020/08/25/%E6%B7%B1%E5%85%A5%E5%AD%A6%E4%B9%A0js-%E6%89%8B%E5%86%99promise%E6%BA%90%E7%A0%81/">深入学习js--手写promise源码...</a>
            <p class="hot-article-stats x-no">共 928 字</p>
          </div>
      </li>
      
    </ul>
  </div>
</div>
    
      
  <div class="card" style="width: auto;margin-bottom: 10px;">
    <div class="card-body">
      <h5 class="card-title">标签云</h5>
      <ul class="list-groups list-group-flush">
        <a href="/tags/ajax/" style="font-size: 10px;">ajax</a> <a href="/tags/asyn/" style="font-size: 10px;">asyn</a> <a href="/tags/bootstrap/" style="font-size: 10px;">bootstrap</a> <a href="/tags/chrome/" style="font-size: 10px;">chrome</a> <a href="/tags/cookie/" style="font-size: 10px;">cookie</a> <a href="/tags/css3/" style="font-size: 13.33px;">css3</a> <a href="/tags/deno/" style="font-size: 10px;">deno</a> <a href="/tags/django/" style="font-size: 16.67px;">django</a> <a href="/tags/ejs/" style="font-size: 20px;">ejs</a> <a href="/tags/es6/" style="font-size: 15px;">es6</a> <a href="/tags/generator/" style="font-size: 10px;">generator</a> <a href="/tags/git/" style="font-size: 11.67px;">git</a> <a href="/tags/github/" style="font-size: 11.67px;">github</a> <a href="/tags/grid/" style="font-size: 10px;">grid</a> <a href="/tags/hexo/" style="font-size: 13.33px;">hexo</a> <a href="/tags/html/" style="font-size: 11.67px;">html</a> <a href="/tags/html5/" style="font-size: 10px;">html5</a> <a href="/tags/js/" style="font-size: 13.33px;">js</a> <a href="/tags/js%E6%8F%92%E4%BB%B6/" style="font-size: 10px;">js插件</a> <a href="/tags/live2d/" style="font-size: 10px;">live2d</a> <a href="/tags/nexo/" style="font-size: 18.33px;">nexo</a> <a href="/tags/node/" style="font-size: 10px;">node</a> <a href="/tags/opp/" style="font-size: 10px;">opp</a> <a href="/tags/promise/" style="font-size: 10px;">promise</a> <a href="/tags/proxy/" style="font-size: 10px;">proxy</a> <a href="/tags/python/" style="font-size: 10px;">python</a> <a href="/tags/vue/" style="font-size: 13.33px;">vue</a> <a href="/tags/webpack/" style="font-size: 10px;">webpack</a> <a href="/tags/%E4%BC%98%E5%8C%96/" style="font-size: 10px;">优化</a> <a href="/tags/%E5%AD%A6%E4%B9%A0/" style="font-size: 15px;">学习</a> <a href="/tags/%E5%B8%83%E5%B1%80/" style="font-size: 10px;">布局</a> <a href="/tags/%E6%B5%8B%E8%AF%95/" style="font-size: 10px;">测试</a> <a href="/tags/%E7%94%9F%E6%B4%BB/" style="font-size: 10px;">生活</a> <a href="/tags/%E8%B7%A8%E5%9F%9F/" style="font-size: 10px;">跨域</a> <a href="/tags/%E8%BD%AC%E8%BD%BD/" style="font-size: 10px;">转载</a>
      </ul>
    </div>
  </div>
  
    
      

<div class="card" style="width: auto;margin-bottom: 10px;">
  <div class="card-body">
    <h5 class="card-title">归档</h5>
    <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/03/">2021-03</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/09/">2020-09</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/08/">2020-08</a><span class="archive-list-count">5</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/07/">2020-07</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/05/">2020-05</a><span class="archive-list-count">20</span></li></ul>
  </div>
</div>



    

  
   
    
  </div>
    
    
<div class="col-md-9 x-side-content">
    <div class="x-blog-info">
        <div class="x-blog-text">
            <p class="x-no x-blog-title">vue响应式原理--Object.defineProperty & proxy 
            </p>
        </div>
        <div class="x-blog-meta">
            <div class="x-blog-date">
                <i class="iconfont icon-time1"></i>
                <span>2020-08-22 20:44:57 </span>
            </div>
            <div class="x-blog-views">
                <i class="iconfont icon-jianpan"></i>
                <span>字数: 1.8k</span>
            </div>
            <div id="/2020/08/22/vue%E5%93%8D%E5%BA%94%E5%BC%8F%E5%8E%9F%E7%90%86-Object-defineProperty-proxy/" data-flag-title="vue响应式原理--Object.defineProperty &amp; proxy" class="x-blog-comments leancloud-visitors">
                <i class="iconfont icon-view"></i>
               
                <span class="leancloud-visitors-count">loading...</span> <span>&nbsp;访问量</span>
            </div>
          
        </div>
    </div>
    <div class="container x-blog-content">
        <h1 id="深入理解vue响应式原理"><a href="#深入理解vue响应式原理" class="headerlink" title="深入理解vue响应式原理"></a>深入理解vue响应式原理</h1><p>学习<code>vue</code>有一段时间了，<code>vue</code>中核心思想就是数据响应式，实现了数据的双向绑定，减少了操作dom频次。</p>
<p>相信大家都有这个疑惑</p>
<ol>
<li><p>Vue 内部是如何监听数据的改变？</p>
<ul>
<li>vue2.x 采用Object.defineProperty -&gt; 监听对象属性的改变</li>
<li>vue3.x 采用proxy代理来实现  -&gt; 监听对象属性的改变</li>
</ul>
</li>
<li><p>数据发生改变时，Vue是如何知道要通知哪些数据发送变换？</p>
<ul>
<li>答案是发布者订阅模式</li>
</ul>
</li>
</ol>
<p>响应式的原理可以通过这个图片来理解</p>
<p><img src="https://img-blog.csdnimg.cn/20190411134145282.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dvbGRwcm9n,size_16,color_FFFFFF,t_70" alt=""></p>
<p>在<code>vue2.x</code>版本里 作者是利用<code>Object.defineProperty</code>中的get和set来实现数据劫持，从而绑定一些响应事件来达到数据响应式的效果</p>
<blockquote>
<p><code>Object.defineProperty()</code> 方法会直接在一个对象上定义一个新属性，或者修改一个对象的现有属性，并返回此对象。</p>
</blockquote>
<blockquote>
<p>get<br>属性的 <code>getter</code> 函数，如果没有 <code>getter</code>，则为 <code>undefined</code>。当访问该属性时，会调用此函数。执行时不传入任何参数，但是会传入 <code>this</code> 对象（由于继承关系，这里的<code>this</code>并不一定是定义该属性的对象）。该函数的返回值会被用作属性的值。<br>默认为 <code>undefined</code>。</p>
</blockquote>
<blockquote>
<p>set<br>属性的 <code>setter</code> 函数，如果没有 <code>setter</code>,则为 <code>undefined</code>。当属性值被修改时，会调用此函数。该方法接受一个参数（也就是被赋予的新值），会传入赋值时的 <code>this</code> 对象。<br>默认为 <code>undefined</code>。</p>
</blockquote>
<p>每当我们访问或者修改<code>vue</code>实列<code>data</code>里面的数据时，就会触发<code>get</code>和<code>set</code>的回调函数，所以再加上<code>vue</code>的发布者订阅模式就可以实现数据响应式了</p>
<p>以下是手写的响应式代码</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><code class="hljs js">  <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Vue</span> </span>&#123;<br><br>    <span class="hljs-keyword">constructor</span>(options=&#123;&#125;)&#123;<br>      <span class="hljs-keyword">this</span>.el = <span class="hljs-built_in">document</span>.querySelector(options.el)<br>      <span class="hljs-keyword">this</span>.data = options.data()<br>      <span class="hljs-keyword">this</span>.Observe(<span class="hljs-keyword">this</span>.data)<br>      <span class="hljs-keyword">this</span>.Compiler(<span class="hljs-keyword">this</span>.el)<br>    &#125;<br>    <br>    Observe(data, vm)&#123;<br>     <br>      <span class="hljs-built_in">Object</span>.keys(data).forEach(<span class="hljs-function"><span class="hljs-params">key</span> =&gt;</span> &#123;<br>        <span class="hljs-keyword">const</span> dep = <span class="hljs-keyword">new</span> Dep() <br>        <span class="hljs-comment">/* 实现一对多的数据更新 页面中重复多个地方使用同一数据时，统一更新  也就是一个data对应一个dep对象*/</span><br>        <span class="hljs-comment">/*</span><br><span class="hljs-comment">        例如现在的实列数据data中</span><br><span class="hljs-comment">          message -&gt; dep</span><br><span class="hljs-comment">          name -&gt; dep</span><br><span class="hljs-comment">        */</span><br>        <span class="hljs-keyword">let</span> value = data[key]<br>       <br>        <span class="hljs-comment">/* 绑定了set和get事件 只要访问或者修改属性 就会触发回调函数*/</span><br>        <span class="hljs-built_in">Object</span>.defineProperty(data, key, &#123;<br>          <span class="hljs-keyword">set</span>(newValue)&#123;<br>          <br>            <span class="hljs-comment">/* 监听到了改变，告诉订阅者发送改变 */</span><br>            <span class="hljs-keyword">if</span>(newValue !== value) &#123;<br>              value = newValue<br>              dep.notify()<br>            &#125;<br>          &#125;,<br>          <span class="hljs-keyword">get</span>()&#123;<br>         <br>            <span class="hljs-keyword">if</span>(Dep.target) &#123;<br>              dep.addSubs(Dep.target)<br>             <span class="hljs-built_in">console</span>.log(dep);<br>            &#125;<br>            <span class="hljs-keyword">return</span> value<br>          &#125;<br>        &#125;)<br>      &#125;)<br>    &#125;<br>  <br>    Compiler(el)&#123;<br>      <span class="hljs-comment">/* 获取要渲染的dom内容 */</span><br>      <span class="hljs-keyword">const</span> _this = <span class="hljs-keyword">this</span> <span class="hljs-comment">/* 防止this指向发生改变 */</span><br>      <span class="hljs-keyword">const</span> childrens = el.children<br><br>      <span class="hljs-keyword">if</span>(!childrens.length) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(el.id + <span class="hljs-string">'挂载元素里面内容为空！'</span>)<br>      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; childrens.length; i++ )&#123;<br>        <span class="hljs-keyword">const</span> node = childrens[i]<br><br>        <span class="hljs-comment">/* 获取有v-text属性的dom 实施渲染 */</span><br>        <span class="hljs-keyword">if</span>(node.hasAttribute(<span class="hljs-string">'v-text'</span>))&#123;<br>          <span class="hljs-keyword">const</span> dataName = node.getAttribute(<span class="hljs-string">'v-text'</span>)<br>          <span class="hljs-keyword">new</span> Watcher(dataName, node, _this, <span class="hljs-string">'innerHTML'</span>)<br>        &#125;<br>        <span class="hljs-keyword">if</span>(node.hasAttribute(<span class="hljs-string">'v-model'</span>)) &#123;<br>          <span class="hljs-keyword">const</span> dataName = node.getAttribute(<span class="hljs-string">'v-model'</span>)<br>          <span class="hljs-keyword">new</span> Watcher(dataName, node, _this, <span class="hljs-string">'value'</span>)<br>          node.addEventListener(<span class="hljs-string">'input'</span>, (<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>&#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>&#123;<br>              <span class="hljs-keyword">this</span>.data[dataName] = node.value<br>            &#125;<br>          &#125;)().bind(<span class="hljs-keyword">this</span>))<br>        &#125;<br>      &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>上面的代码中在 <code>new Vue</code>的时候，内部会触发一个<code>Observer</code>劫持监听所有属性，同时产生<code>dep</code>发布者，当属性触发<code>set</code>或者<code>get</code>时<code>dep</code>就通知或者添加订阅者</p>
<p>还会有一个<code>Compiler</code>解析指令，订阅数据变化，添加<code>Watcher</code>订阅者，在watcher里面会有一个update的方法，用于更新数据。在<code>Observer</code>里面会通过<code>Object.definepropry</code>方法对数据进行劫持，在<code>get</code>中添加依赖所依赖的<code>watcher</code>，当触发<code>set</code>时说明有数据变化，此时调用<code>dep.notify</code>方法，<code>dep.notify</code>又会触发<code>watcher</code>的<code>update</code>方法来更新数据</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><code class="hljs js">  <span class="hljs-comment">/* 发布者订阅者模式 */</span><br><span class="hljs-comment">/* 发布者 */</span><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dep</span> </span>&#123;<br><br>  <span class="hljs-keyword">constructor</span>()&#123;<br>    <span class="hljs-keyword">this</span>.target = <span class="hljs-literal">null</span><br>    <span class="hljs-comment">/* 记录订阅者 */</span><br>    <span class="hljs-keyword">this</span>.subs = []<br>  &#125;<br><br>  addSubs(watcher)&#123;<br>    <span class="hljs-keyword">this</span>.subs.push(watcher)<br>  &#125;<br><br>  notify()&#123;<br>    <span class="hljs-keyword">this</span>.subs.forEach(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> &#123;<br>      item.update()<br>    &#125;)<br>  &#125;<br><br>&#125;<br><span class="hljs-comment">/* 订阅者 */</span><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Watcher</span> </span>&#123;<br><br>  <span class="hljs-keyword">constructor</span>(name, el, vm, attr)&#123;<br>    <span class="hljs-keyword">this</span>.name = name<br>    <span class="hljs-keyword">this</span>.el = el <br>    <span class="hljs-keyword">this</span>.vm = vm<br>    <span class="hljs-keyword">this</span>.attr = attr<br>    <span class="hljs-keyword">this</span>.update()<br>  &#125;<br><br>  update()&#123;<br>    <span class="hljs-comment">/* 更新页面 实现响应式 */</span><br>    Dep.target = <span class="hljs-keyword">this</span> <span class="hljs-comment">// 释放当前订阅者 </span><br>    <span class="hljs-comment">//console.log(this.name + '发送了更新----');</span><br><br>    <span class="hljs-keyword">this</span>.el[<span class="hljs-keyword">this</span>.attr] = <span class="hljs-keyword">this</span>.vm.data[<span class="hljs-keyword">this</span>.name] <span class="hljs-comment">//执行到这时会触发get回调，所以Dep会获取到当前的watcher</span><br>    Dep.target = <span class="hljs-literal">null</span> <span class="hljs-comment">// 释放当前订阅者 </span><br>  &#125;<br><br>&#125;<br></code></pre></td></tr></table></figure>

<h1 id="实列代码"><a href="#实列代码" class="headerlink" title="实列代码"></a>实列代码</h1><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>vue响应式实现<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><br><span class="css">      <span class="hljs-selector-id">#app</span> &#123;</span><br>        position: fixed;<br>        left: 50%;<br>        top: 50%;<br>        transform: translate(-50%,-50%);<br><span class="css">        <span class="hljs-selector-tag">background</span>: <span class="hljs-selector-id">#f6f6f6</span>;</span><br>        border: 1px solid salmon;<br>        min-width: 500px;<br>        min-height: 500px;<br>      &#125;<br>      div&#123;<br><span class="css">        <span class="hljs-selector-tag">padding</span><span class="hljs-selector-pseudo">:10px</span>;</span><br>        font-weight: 500;<br>      &#125;<br>    <span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span><br>      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-text</span>=<span class="hljs-string">'message'</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-text</span>=<span class="hljs-string">'message'</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-text</span>=<span class="hljs-string">'name'</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-text</span>=<span class="hljs-string">'name'</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-text</span>=<span class="hljs-string">'message'</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br>      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"phone"</span>&gt;</span><br>      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"phone"</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"../vue.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span><br><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><br>  <br><span class="actionscript"><span class="hljs-keyword">const</span> App = <span class="hljs-keyword">new</span> Vue(&#123;</span><br><span class="actionscript">  el: <span class="hljs-string">"#app"</span>,</span><br>  data()&#123;<br><span class="actionscript">    <span class="hljs-keyword">return</span> &#123;</span><br><span class="actionscript">      message: <span class="hljs-string">"hello world"</span>,</span><br><span class="actionscript">      name: <span class="hljs-string">"xowen"</span>,</span><br><span class="actionscript">      phone: <span class="hljs-string">"1567489789"</span></span><br>    &#125;<br>  &#125;<br>&#125;)<br><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span><br></code></pre></td></tr></table></figure>
<h1 id="运行效果"><a href="#运行效果" class="headerlink" title="运行效果"></a>运行效果</h1><p><img src="https://s1.ax1x.com/2020/08/22/dd3RjU.png" alt=""><br><img src="https://s1.ax1x.com/2020/08/22/dd32cT.png" alt=""></p>
<h1 id="使用proxy代理"><a href="#使用proxy代理" class="headerlink" title="使用proxy代理"></a>使用proxy代理</h1><blockquote>
<p>Proxy 用于修改某些操作的默认行为，等同于在语言层面做出修改，所以属于一种“元编程”（meta programming），即对编程语言进行编程。<br>Proxy 可以理解成，在目标对象之前架设一层“拦截”，外界对该对象的访问，都必须先通过这层拦截，因此提供了一种机制，可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理，用在这里表示由它来“代理”某些操作，可以译为“代理器”。</p>
</blockquote>
<p>下面是另一个拦截读取属性行为的例子。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">var</span> proxy = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Proxy</span>(&#123;&#125;, &#123;<br>  <span class="hljs-keyword">get</span>: function(target, propKey) &#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-number">35</span>;<br>  &#125;<br>&#125;);<br><br>proxy.time  <span class="hljs-comment">// 35</span><br>proxy.name  <span class="hljs-comment">// 35</span><br>proxy.title <span class="hljs-comment">// 35</span><br></code></pre></td></tr></table></figure>
<p>上面代码中，作为构造函数，Proxy接受两个参数。第一个参数是所要代理的目标对象（上例是一个空对象），即如果没有Proxy的介入，操作原来要访问的就是这个对象；第二个参数是一个配置对象，对于每一个被代理的操作，需要提供一个对应的处理函数，该函数将拦截对应的操作。比如，上面代码中，配置对象有一个get方法，用来拦截对目标对象属性的访问请求。get方法的两个参数分别是目标对象和所要访问的属性。可以看到，由于拦截函数总是返回35，所以访问任何属性都得到35。<br>深入学习proxy可以点击查看<a href="https://es6.ruanyifeng.com/#docs/proxy" target="_blank" rel="noopener">这篇文章</a></p>
<p><code>vue</code>中使用proxy</p>
<p>我们只需要使用proxy重写Observe方法就行了</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Vue</span> </span>&#123;<br>  <span class="hljs-keyword">constructor</span>()&#123;<br>    ···<br>  &#125;<br>  Observe(data)&#123;<br>    ···<br>    <span class="hljs-keyword">this</span>.data = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Proxy</span>(data,&#123;<br>        <span class="hljs-keyword">get</span>:function(target,key,reveive)&#123;<br>          <span class="hljs-keyword">if</span>(Dep.target)&#123;<br>            <span class="hljs-comment">/* 添加订阅者 */</span><br>          &#125;<br>          <span class="hljs-keyword">return</span> target[key]<br>        &#125;,<br>        <span class="hljs-keyword">set</span>:function (target, key, newValue,reveive)&#123;<br>          <span class="hljs-keyword">if</span>(target[key] !== newValue)&#123;<br>            target[key] = newValue;<br>            <span class="hljs-comment">/* 通知订阅者更新 */</span><br>          &#125;<br>        &#125;<br>    &#125;)<br>  &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
<hr>

    </div>
    <div class="pageLocate">
       <div class="col-md-6">
    
        
            
            <p><a href="/2020/08/23/Vue模仿蘑菇街移动商城开发/">上一章:&nbsp;<span>Vue模仿蘑菇街...</span></a></p>
           
        
       </div>
       <div class="col-md-6" >
        
            
            <p style="text-align: right;"><a href="/2020/08/11/知乎问答网站仿写-调用API接口/">下一章:&nbsp;<span>知乎问答网站仿写...</span></a></p>
            
        
       </div>
    </div>
    <div class="x-blog-footer">
        
            <section id="comments" class="comments">
              <style>
                .comments{margin:30px;padding:10px;}
                @media screen and (max-width:800px){.comments{margin:auto;padding:10px;background:#fff}}
              </style>
              <div class="valine_comment"></div>
<!--载入js，在</body>之前插入即可-->
<!--Leancloud 操作库:-->
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<!--Valine 的核心代码库-->
<script src="//unpkg.com/valine/dist/Valine.min.js"></script>
<script>
  new Valine({
      el: '.valine_comment',
      app_id: 'kEVKhcTQTMzzN0RQplG6qnm1-gzGzoHsz',
      app_key: 'nLyVp65cwTByxpxImBDCLmaT',
      placeholder: '一起讨论吧',
      notify: 'true',
      verify: 'true',
      visitor: 'true',
    });
</script>
            </section>
          
    </div>
</div>



      </div>
    </div>
    <script src="https://cdn.bootcdn.net/ajax/libs/highlight.js/10.0.1/highlight.min.js"></script>
    <script>hljs.initHighlightingOnLoad();</script>
      <!-- live2d model -->
      <div class="live2d-box">
  <canvas id="glcanvas" width="300" height="350">
                    
  </canvas>
  <div class="live2d-msg">
      <p class="live2d-info-text">
        君子阳阳，左执簧，右招我由房，其乐只且！
君子陶陶，左执翿，右招我由敖，其乐只且！
      </p>
    </div>  
    <div class="spinner">
      <div class="rect1"></div>
      <div class="rect2"></div>
      <div class="rect3"></div>
      <div class="rect4"></div>
      <div class="rect5"></div>
    </div>
</div>


  <script src="/js/live2d/lib/live2d.min.js"></script>

  <script src="/js/live2d/framework/Live2DFramework.js"></script>

  <script src="/js/live2d/utils/MatrixStack.js"></script>

  <script src="/js/live2d/utils/ModelSettingJson.js"></script>
  <script src="/js/live2d/PlatformManager.js"></script>
  <script src="/js/live2d/LAppDefine.js"></script>
  <script src="/js/live2d/LAppModel.js"></script>
  <script src="/js/live2d/LAppLive2DManager.js"></script>
  <script src="/js/live2d/SampleApp1.js"></script>
  <script>sampleApp1();</script>


 
    <!-- partial model -->
   
    <script src="/js/running.js"></script>
    <!-- footer  -->
    <!-- <div class="tools-search" data-toggle="modal" data-target="#myModal"> 
  <i class="iconfont x-no icon-search" ></i>
</div>

<div class="tools-music" data-toggle="modal" data-target="#wyymusic"> 
  <i class="iconfont x-no icon-ziyuanldpi" ></i>
</div> -->

<!-- bg -->


<!-- search -->
<div class="fixed-back ani-box">
  <i class="iconfont x-no icon-upa"></i>
</div>

<a href="/">
<div class="fixed-home ani-box">
  <i class="iconfont x-no icon-xuanzhongshangcheng"></i>
</div>
</a>

<div class="fixed-switch ani-box">
  <i class="iconfont x-no icon-kaiguan1"></i>
</div>
<div class="fixed-bg">

</div>
<div class="fixed-bg-cover ani-box" id="fixed_bg_cover">

</div>

<div class="container-fluid x-footer ani-box" >
    <p class="web-info x-no">
      Copyright © 2020 Xowen [www.xowen.cn] All Rights Reserved
    </p>
    <p class="web-info x-no">
      Power By<span> &nbsp;Xowen</span>
  
    </p>
    <p class="web-info x-no">
     
      部分图片引用自网络，如有侵权请联系我。
            
  
    </p>
  </div>
  
  <script type="text/javascript">
    /* 鼠标特效 */
    var a_idx = 0;
    jQuery(document).ready(function($) {
        $("body").click(function(e) {
            var a = new Array("富强","民主","文明","和谐","自由","平等","公正","法治","爱国","敬业","诚信","友善");
            var $i = $("<span></span>").text(a[a_idx]);
            a_idx = (a_idx + 1) % a.length;
            var x = e.pageX,
            y = e.pageY;
            $i.css({
                "z-index": 999999999999999999999999999999999999999999999999999999999999999999999,
                "top": y - 20,
                "left": x,
                "position": "absolute",
                "font-weight": "bold",
                "color": "rgb("+~~(255*Math.random())+","+~~(255*Math.random())+","+~~(255*Math.random())+")",
                "font-size": "0.8rem"
            });
            $("body").append($i);
            $i.animate({
                "top": y - 180,
                "opacity": 0
            },
            1500,
            function() {
                $i.remove();
            });
        });
    });
    </script>    <!-- 鼠标跟随 -->
    <!-- <script>
      let myBody = document.querySelector('body');
      // console.log(myBody);
      document.onmouseover = (e)=> {
        
        myBody.style.transform = "translateY(30px)"
      } -->
    </script>
</body>

</html>